/*
 * Copyright 2003-2005 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

using System;
using DynamicTypeMap = argot.DynamicTypeMap;
using TypeElement = argot.TypeElement;
using TypeException = argot.TypeException;
using TypeMapCore = argot.TypeMapCore;
using TypeOutputStream = argot.TypeOutputStream;
using TypeLibrary = argot.TypeLibrary;
using MetaDefinition = argot.meta.MetaDefinition;
namespace argot.message
{
	
	public class MessageWriter
	{
		private TypeLibrary _library;
		
		public MessageWriter(TypeLibrary library)
		{
			_library = library;
		}
		
		public virtual void  writeMessage(System.IO.Stream outStream, System.String type, System.Object object_Renamed)
		{
			
			// create and bind types for dictionary.
			
			// write out the dictionary used to write the content.
			TypeMapCore refCore = TypeMapCore.GetCoreTypeMap(_library);
			refCore.Map(22, _library.GetId("dictionary.map"));
			refCore.Map(23, _library.GetId("dictionary.words"));
			refCore.Map(24, _library.GetId("dictionary.definition"));
			refCore.Map(25, _library.GetId("dictionary.entry"));
			refCore.Map(26, _library.GetId("meta.envelop"));
			refCore.Map(27, _library.GetId("meta.definition#envelop"));
			
			// get the core type map.
			
			// write out the dictionary used to write the content.
			TypeMapCore core = TypeMapCore.GetCoreTypeMap(_library, refCore);
			core.Map(22, _library.GetId("dictionary.map"));
			core.Map(23, _library.GetId("dictionary.words"));
			core.Map(24, _library.GetId("dictionary.definition"));
			core.Map(25, _library.GetId("dictionary.entry"));
			core.Map(26, _library.GetId("meta.envelop"));
			core.Map(27, _library.GetId("meta.definition#envelop"));
			
			// create a dynamic type map.
			DynamicTypeMap dtm = new DynamicTypeMap(_library);
			
			// write out the message content.  Definition of the core type map.
			System.IO.MemoryStream baos = new System.IO.MemoryStream();
			TypeOutputStream tmos = new TypeOutputStream(baos, dtm);
			tmos.WriteObject("u16", (System.Object) dtm.GetId(_library.GetId(type)));
			tmos.WriteObject(type, object_Renamed);
			tmos.Stream.Close();
			baos.Close();

			// problem is that in writing the dtm, new types might
			// need to be dynamically added.  Simple solution is to 
			// write it twice.
			core.ReferenceMap = dtm;
			System.IO.MemoryStream baos2 = new System.IO.MemoryStream();
			TypeOutputStream tmos2 = new TypeOutputStream(baos2, core);
			tmos2.WriteObject("u8", (System.Object) 1);
			tmos2.WriteObject("dictionary.words", dtm);
			tmos2.Stream.Close();
			baos2.Close();
			
			baos2 = new System.IO.MemoryStream();
			tmos2 = new TypeOutputStream(baos2, core);
			tmos2.WriteObject("u8", (System.Object) 1);
			tmos2.WriteObject("dictionary.words", dtm);
			tmos2.Stream.Close();
			baos2.Close();
			
			// write out the core used to write the message dictionary.
			core.ReferenceMap = refCore;
			System.IO.MemoryStream baos3 = new System.IO.MemoryStream();
			TypeOutputStream tmos3 = new TypeOutputStream(baos3, core);
			writeCoreMap(tmos3, core);
			tmos3.Stream.Close();
			baos3.Close();
			
			// write out the file.
			byte[] temp_array3 = baos3.ToArray();
			outStream.Write( temp_array3, 0, temp_array3.Length);

			byte[] temp_sbyteArray;
			temp_sbyteArray = baos2.ToArray();
			outStream.Write(temp_sbyteArray, 0, temp_sbyteArray.Length);

			byte[] temp_sbyteArray2;
			temp_sbyteArray2 = baos.ToArray();
			outStream.Write(temp_sbyteArray2, 0, temp_sbyteArray2.Length);

		}
		
		private static void  writeCoreMap(TypeOutputStream outStream, TypeMapCore map)
		{
			// writing out the core and then the extensions.
			outStream.WriteObject("U8", (System.Object) 2);
			
			// write out the core elements.
			System.Collections.IList coreIds = argot.TypeMapCore.CoreIdentifiers;
			System.IO.MemoryStream baos1 = new System.IO.MemoryStream();
			TypeOutputStream out1 = new TypeOutputStream(baos1, map);
			
			// write the number of entries.
			out1.WriteObject("U16", (System.Object) coreIds.Count);
			
			
			System.Collections.IEnumerator i = coreIds.GetEnumerator();
			while (i.MoveNext())
			{
				int id = ((System.Int32) i.Current);
				System.String name = map.GetName(id);
				TypeElement definition = (TypeElement) map.GetStructure(id);
				
				out1.WriteObject("U16", (System.Object) id);
				out1.WriteObject("meta.name", name);
				out1.WriteObject("dictionary.definition", definition);
			}
			
			out1.Stream.Close();
			baos1.Close();
			
			byte[] coreBuffer = baos1.ToArray();
			outStream.WriteObject("u16", (System.Object) coreBuffer.Length);
			outStream.Stream.Write(coreBuffer,0,coreBuffer.Length);
			
			// write out extensions.
			
			System.IO.MemoryStream baos2 = new System.IO.MemoryStream();
			TypeOutputStream out2 = new TypeOutputStream(baos2, map);
			
			
			// count the number of extensions
			int extensionCount = 0;
			i = map.Iterator;
			while (i.MoveNext())
			{
				System.Int32 id = (System.Int32) i.Current;
				if (coreIds.Contains(id))
				{
					// already written this out in the core.
					continue;
				}
				extensionCount++;
			}
			
			out2.WriteObject("U16", (System.Object) extensionCount);
			
			// write out the extensions
			i = map.Iterator;
			while (i.MoveNext())
			{
				System.Int32 id = (System.Int32) i.Current;
				if (coreIds.Contains(id))
				{
					// already written this out in the core.
					continue;
				}
				System.String name = map.GetName(id);
				MetaDefinition definition = (MetaDefinition) map.GetStructure(id);
				
				out2.WriteObject("U16", (System.Object) id);
				out2.WriteObject("meta.name", name);
				out2.WriteObject("dictionary.definition", definition);
			}
			
			out2.Stream.Close();
			baos2.Close();
			
			byte[] extBuffer = baos2.ToArray();
			outStream.WriteObject("u16", (System.Object) extBuffer.Length);
			outStream.Stream.Write(extBuffer,0,extBuffer.Length);
		}
	}
}